/******************************************************************************
//             INTEL CORPORATION PROPRIETARY INFORMATION
//  This software is supplied under the terms of a license agreement or
//  nondisclosure agreement with Intel Corporation and may not be copied
//  or disclosed except in accordance with the terms of that agreement.
//    Copyright(c) 2000 - 2001 Intel Corporation. All Rights Reserved.
//
//  VSS: 
//     $Workfile: $
//     $Revision: $
//     $Date:     $
//     $Archive:  $
//
//  Description:
//      Intel(R) Integrated Performance Primitives - JPEG Helper file.
//      This file contains shared functions for Huffman decoding.
//
//  History:
//     Date         Author        Changes
//     2000/5/20   Jerry Hu       Created  (Version 0.1)
//     2001/1/21   Jerry Hu       Modified (Version 0.2)
//
********************************************************************************/
#include "_ippjpeg.h"
#include "ijdhufsh.h"

/* For negative value */
const int _nLowestCoef[]=
{
   0,     -1,     -3,      -7,
   -15,   -31,    -63,     -127,
   -255,  -511,   -1023,   -2047,
   -4095, -8191,  -16383,  -32767
};

/* Minimum allowable value */
#define _HUFF_PREVIEWEDBITS  16
#define _HUFF_LOOKEDBITS     8

/******************************************************************************
// Name:             _IppPrefetchBits
// Description:      Copy '_HUFF_PREVIEWEDBITS' bits from stream buffer to 
//                   preview buffer for decoding. 
// Input Arguments:     
//          pStream: Identifies the internal structure of stream buffer.  
// Output Arguments:
//                    none.  
// Returns:         
//                    Number of valid bits in preview buffer  
//
******************************************************************************/
int _IppPrefetchBits(_stream *pStream)
{
    Ipp8u code;
    /*int  nCount;*/

    if (0<(*(pStream->pMarker))) {
        /* Current number of the bits are enough for decoding */
        return (*(pStream->pnNumValidBits));
    }

    while ((*(pStream->pnNumValidBits))<_HUFF_PREVIEWEDBITS) {
        code=*(pStream->pStreamBuffer);
        pStream->pStreamBuffer++;
        pStream->nUsedBytesLen++;
        if (0xff==code) {/* distinguish Marker or Value */
            /*nCount=1;*/
            do{
                code=*(pStream->pStreamBuffer);
                pStream->pStreamBuffer++;
                pStream->nUsedBytesLen++;
                /*nCount++;*/
            } while (0xff==code);

            if (0==code) {
               code=0xff;
            } else { /* found a Marker */
                (*(pStream->pMarker))=code;
                return (*(pStream->pnNumValidBits));
            }
        }

        (*(pStream->pnPrefetchedBits))=((*(pStream->pnPrefetchedBits))<<8)|code;
        (*(pStream->pnNumValidBits))+=8;
    } /* while (pStream->nNumValidBits<_HUFF_PREVIEWEDBITS) */

    return (*(pStream->pnNumValidBits));
} /* _IppPrefetchBits */

/******************************************************************************
// Name:             _IppDecodeLongBits
// Description:      Decode Huffman code bit by bit.
//                   Refer to "F.16 - Procedure for DECODE" in ISO 10918-1  
// Input Arguments: 
//    nNumValidBits: Specifies the minimum bits to be decoded.
//       pHuffTable: Identifies huffman table for decoding.   
//          pStream: Identifies the internal structure of stream buffer.  
//
// Output Arguments:
//                    none.
// Returns:         
//                   Following Huffman code size:
//              [DC] "ssss". 
//              [AC] "rrrrssss".
//
******************************************************************************/
int _IppDecodeLongBits( int  nNumValidBits,
                     const IppJPEGDeHuffTable *pHuffTable,
                     _stream *pStream)
{
    Ipp32s code;
    Ipp32s max;
    int    rtCode=-1;

    /*_CHECKPREVIEWBITSNUM(nNumValidBits, pStream, -1);*/
    _CHECKPREVIEWBITSNUM(nNumValidBits, pStream, -256);
    _GETBITS(code, nNumValidBits, pStream);

    /* Finding bit length */

    max=(Ipp16u)pHuffTable->maxcode[nNumValidBits];

    while (code>max||0xffff==max) {
	Ipp32s code1;
        code <<= 1;
        _CHECKPREVIEWBITSNUM(1, pStream, -256);
        _GETBITS(code1, 1, pStream);
	code |= code1;
        nNumValidBits++;
        max=(Ipp16u)pHuffTable->maxcode[nNumValidBits];
    } 

    if (nNumValidBits>16) {
        rtCode = -1;
    } else {
        int nIndex=pHuffTable->valptr[nNumValidBits] +
                    ((int)(code - pHuffTable->mincode[nNumValidBits]));
        rtCode = pHuffTable->huffVal[nIndex];
    }

    return rtCode;
} /* _IppDecodeLongBits */

/******************************************************************************
// Name:             _IppHuffDecode
// Description:      Fast Huffman decoder. 
//                   if Huffman code size is less than 8 bits, 
//                   use a lookup table for decoding.
//                   Otherwhise, decode it bit by bit.
// Input Arguments: 
//       pHuffTable: Identifies the huffman table for decoding.
//          pStream: Identifies the internal structure of stream buffer.  
//
// Output Arguments:
//                   none.
// Returns:                  
//                   Following Huffman code size:
//              [DC] "ssss". 
//              [AC] "rrrrssss".
//           [Error] -1  
//                  
******************************************************************************/
int _IppHuffDecode(const IppJPEGDeHuffTable *pHuffTable,
                _stream *pStream)
{
    int    rtCode=-1;
    int    nLook;
    int    nNumHuffBits;

    if ((*(pStream->pnNumValidBits))<_HUFF_LOOKEDBITS) {
        if (0>=_IppPrefetchBits(pStream)) {
            return (-256);
        }
        if ((*(pStream->pnNumValidBits))<_HUFF_LOOKEDBITS) {
            _PEEKBITS_S(nLook, _HUFF_LOOKEDBITS, pStream);
        } else {
            _PEEKBITS_L(nLook, _HUFF_LOOKEDBITS, pStream);
        }
    } else {
        _PEEKBITS_L(nLook, _HUFF_LOOKEDBITS, pStream);
    }

    nNumHuffBits = pHuffTable->lookBitsVal[nLook] >> 16;

    if (0!=nNumHuffBits){
        (*(pStream->pnNumValidBits)) -= nNumHuffBits;
        rtCode = pHuffTable->lookBitsVal[nLook]&0xFFFF;
    }
    else{
        nNumHuffBits = _HUFF_LOOKEDBITS+1;
        rtCode = _IppDecodeLongBits(nNumHuffBits, pHuffTable, pStream);
    }

    return rtCode;
} /* _IppHuffDecode */

/* EOF */
